package com.tongcao.cn.service.jenkins;

import com.github.kevinsawicki.http.HttpRequest;
import com.google.common.collect.Maps;
import com.offbytwo.jenkins.JenkinsServer;
import com.offbytwo.jenkins.model.*;
import com.tongcao.cn.util.PropertiesUtils;
import org.dom4j.DocumentException;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.*;

/**
 * @author:tongcao
 * @since:2019/8/5 14:20
 * Description:
 */
public abstract class AbstractJenkinsService implements IJenkinsService {

    protected Map<String, JenkinsServer> jenkinsServerMap;

    private static Map<String, String> properties = new HashMap<>();

    static {
        try {
            properties = PropertiesUtils.readProperties("staticResource.properties");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    enum JenkinsServerEnum {

        JENKINS_NEW(properties.get("new_jenkins.user"), properties.get("new_jenkins.password"), properties.get("new_jenkins.url"));

        private String user;
        private String password;
        private String url;

        JenkinsServerEnum(String user, String password, String url) {
            this.user = user;
            this.password = password;
            this.url = url;
        }

        public String getUser() {
            return user;
        }

        public String getPassword() {
            return password;
        }

        public String getUrl() {
            return url;
        }
    }


    /**
     * 取得全部job
     *
     * @return
     * @throws IOException
     */
    @Override
    public List<Job> getJob() throws IOException {
        final Map<String, Job> jobs = getJenkinsServer().getJobs();
        if (CollectionUtils.isEmpty(jobs)) {
            return Collections.emptyList();
        }
        return new ArrayList<>(jobs.values());
    }

    /**
     * 取得job配置
     *
     * @param jobName job名
     * @return
     * @throws IOException
     */
    @Override
    public String getJobXml(String jobName) throws IOException {
        return getJenkinsServer().getJobXml(jobName);
    }

    /**
     * 取得job
     *
     * @param jobName job名
     * @return
     * @throws IOException
     */
    @Override
    public Job getJob(String jobName) throws IOException {
        return getJenkinsServer().getJob(jobName);
    }

    /**
     * 创建job
     *
     * @param jobName      job名
     * @param xmlConfigStr 配置
     * @return
     * @throws URISyntaxException
     * @throws DocumentException
     * @throws IOException
     */
    @Override
    public String createJob(String jobName, String xmlConfigStr) throws URISyntaxException, DocumentException, IOException {
        for (JenkinsServer server : jenkinsServerMap.values()) {
            if (server.getJob(jobName) == null) {
                server.createJob(jobName, xmlConfigStr, false);
            }
        }
        return jobName;
    }

    /**
     * 更新job配置
     *
     * @param jobName      job名
     * @param xmlConfigStr 配置
     * @return
     * @throws IOException
     */
    @Override
    public void updJobXml(String jobName, String xmlConfigStr) throws IOException {
        for (JenkinsServer server : jenkinsServerMap.values()) {
            if (server.getJob(jobName) != null) {
                server.updateJob(jobName, xmlConfigStr, false);
            }
        }
    }

    /**
     * 删除job
     *
     * @param jobName
     * @throws IOException
     */
    @Override
    public void deleteJob(String jobName) throws IOException {
        for (JenkinsServer server : jenkinsServerMap.values()) {
            if (server.getJob(jobName) != null) {
                server.deleteJob(jobName, false);
            }
        }
    }

    /**
     * 构建任务
     *
     * @param jobName job名字
     * @return
     * @throws IOException
     * @throws InterruptedException
     * @throws URISyntaxException
     */
    @Override
    public Integer buildByJobName(String jobName) throws IOException, InterruptedException, URISyntaxException {
        return buildByJobName(jobName, null);
    }


    private Integer buildByJobName(String jobName, Map<String, String> params) throws IOException {
        final JobWithDetails job = getJenkinsServer().getJob(jobName);
        if (job.details().isBuildable() && (job.details().getLastBuild() != null || !job.details().getLastBuild().details().isBuilding())) {
            final int nextBuildNumber = job.details().getNextBuildNumber();
            if (CollectionUtils.isEmpty(params)) {
                job.build(false);
            } else {
                job.build(params, false);
            }
            return nextBuildNumber;
        } else {
            throw new RuntimeException("job can not be built");
        }
    }

    /**
     * 参数构建任务
     *
     * @param jobName job名字
     * @param params  构建参数
     * @return 构建编号
     * @throws IOException
     * @throws InterruptedException
     * @throws URISyntaxException
     */
    @Override
    public Integer buildByJobNameWithParams(String jobName, Map<String, String> params) throws IOException {
        return buildByJobName(jobName, params);
    }

    /**
     * 取消执行中任务
     *
     * @param jobName job名字
     * @param buildId 编译ID
     * @return
     */
    @Override
    public boolean cancelBuild(String jobName, Integer buildId) throws IOException {
        for (JenkinsServer server : jenkinsServerMap.values()) {
            final JobWithDetails job = server.getJob(jobName);
            if (job != null) {
                final Build lastBuild = job.getLastBuild();
                if (lastBuild.details().isBuilding()) {
                    lastBuild.Stop();
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 取得构建log -text类型
     *
     * @param jobName  任务名
     * @param buildId  编译ID
     * @param textSite 文字位置
     * @return
     * @throws URISyntaxException
     * @throws IOException
     */
    @Override
    public JenkinsLog getLogResumeWithText(String jobName, Integer buildId, Long textSite) throws URISyntaxException, IOException {
        JenkinsServer jenkinsServer = getJenkinsServer();
        BuildWithDetails buildDetail = getJenkinsServer().getJob(jobName).getBuildByNumber(buildId).details();

        String url = URLDecoder.decode(buildDetail.getUrl(), "utf-8") + "logText/progressiveText";

        return getLogResume(url, textSite);
    }


    /**
     * 取得日志
     *
     * @param url      日志链接
     * @param textSite 文字位置
     * @return
     */
    private JenkinsLog getLogResume(String url, Long textSite) {
        if (textSite == null) {
            textSite = 0L;
        }

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("start", textSite);

        HttpResult result = this.get(url, params);

        JenkinsLog log = new JenkinsLog();
        log.setTextSite(Long.parseLong(result.getHeaders().get("X-Text-Size").get(0)));
        log.setLog(result.getBody());
        log.setMoreData(result.getHeaders().get("X-More-Data") != null);

        return log;
    }

    /**
     * 取得view
     *
     * @param viewName view名
     * @return
     * @throws IOException
     */
    @Override
    public View getView(String viewName) throws IOException {
        return getJenkinsServer().getView(viewName);
    }

    /**
     * 创建View
     *
     * @param viewName 视图名称
     */
    @Override
    public void createView(String viewName) {
        try {
            for (Map.Entry<String, JenkinsServer> stringJenkinsServerEntry : jenkinsServerMap.entrySet()) {
                createView(viewName, stringJenkinsServerEntry.getValue(), stringJenkinsServerEntry.getKey());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }


    private void createView(String viewName, JenkinsServer server, String url) {
        View view;
        try {
            view = server.getView(viewName);

        } catch (IOException e) {
            view = null;
        }
        if (view == null) {
            url += "creatView";
            Map<String, Object> param = Maps.newHashMap();
            param.put("name", viewName);
            this.post(url, param, this.getClass().getClassLoader().getResourceAsStream("jenkins-view-config.xml"));
        }
    }

    /**
     * 删除视图
     *
     * @param viewName 视图名称
     * @throws IOException
     */
    @Override
    public void deleteView(String viewName) throws IOException {

    }

    /**
     * 添加job到视图
     *
     * @param jobName  job名称
     * @param viewName 视图名称
     * @throws IOException
     */
    @Override
    public void addJob2View(String jobName, String viewName) throws IOException {

    }

    /**
     * 取得构建log -html类型
     *
     * @param jobName  任务名
     * @param buildId  编译ID
     * @param textSite 文字位置
     * @return
     * @throws IOException
     */
    @Override
    public JenkinsLog getLogResumeWithHtml(String jobName, Integer buildId, Long textSite) throws IOException {
        return null;
    }

    /**
     * 子类实现
     *
     * @return
     */
    @Override
    public abstract JenkinsServer getJenkinsServer();

    @Override
    public String getViewXml(String viewName) {
        return null;
    }

    /**
     * 更新view
     *
     * @param viewName
     * @param newViewName
     * @throws IOException
     */
    @Override
    public void changeViewName(String viewName, String newViewName) throws IOException {

    }


    private HttpResult get(String url) {
        return this.get(url, null, null);
    }

    private HttpResult get(String url, Map<String, Object> params) {
        return this.get(url, params, null);
    }

    /**
     * get请求
     *
     * @param url    请求地址
     * @param params 提交变量
     * @param xmlIs  xml文件读取流
     * @return
     */
    private HttpResult get(String url, Map<String, Object> params, InputStream xmlIs) {
        HttpRequest request = HttpRequest.get(url, params, true);
        Map<String, String> user = getUserMap(url);
        //认证信息添加
        request.basic(user.get("userId"), user.get("userPassword"));
        if (xmlIs != null) {
            request.contentType("text/xml", "utf-8");
            request.send(xmlIs);
        }

        return request2Obj(request, false);
    }

    private HttpResult post(String url) {
        return this.post(url, null, null, false);
    }

    private HttpResult post(String url, Boolean ignore403Err) {
        return this.post(url, null, null, ignore403Err);
    }

    private HttpResult post(String url, Map<String, Object> params) {
        return this.post(url, params, null, false);
    }

    private HttpResult post(String url, Map<String, Object> params, Boolean ignore403Err) {
        return this.post(url, params, null, ignore403Err);
    }

    private HttpResult post(String url, Map<String, Object> params, InputStream xmlIs) {
//        return this.post(url, params, xmlIs, false);
        return this.post(url, params, xmlIs, true);
    }

    /**
     * post请求
     *
     * @param url    请求地址
     * @param params 提交变量
     * @param xmlIs  xml文件读取流
     * @return
     */
    private HttpResult post(String url, Map<String, Object> params, InputStream xmlIs, boolean ignore403Err) {
        HttpRequest request = HttpRequest.post(url, params, true);

        Map<String, String> user = getUserMap(url);
        //认证信息添加
        request.basic(user.get("userId"), user.get("userPassword"));
        if (xmlIs != null) {
            request.contentType("text/xml", "utf-8");
            request.send(xmlIs);
        }

        return request2Obj(request, ignore403Err);
    }

    /**
     * 请求对象生成
     *
     * @param request
     */
    private HttpResult request2Obj(HttpRequest request, boolean ignore403Err) {
        if (request.code() != 200 && request.code() == 403 && !ignore403Err) {
            throw new RuntimeException(request.code() + " " + request.message());
        }

        HttpResult result = new HttpResult();
        result.setBody(request.body());
        result.setHeaders(request.headers());

        return result;
    }

    /**
     * 请求返回对象
     */
    private static class HttpResult {
        private String body;

        private Map<String, List<String>> headers;

        public String getBody() {
            return body;
        }

        public void setBody(String body) {
            this.body = body;
        }

        public Map<String, List<String>> getHeaders() {
            return headers;
        }

        public void setHeaders(Map<String, List<String>> headers) {
            this.headers = headers;
        }
    }

    @Override
    public ComputerSet getComputerSet() {

        //  JenkinsServer jenkinsServer = getJenkinsServer();
        ComputerSet computerSet;
        try {
            computerSet = getJenkinsServer().getComputerSet();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return computerSet;
    }


    private Map<String, String> getUserMap(String url) {
        Map<String, String> userMap = new HashMap<>();
        for (JenkinsServerEnum jenkinsServerEnum : JenkinsServerEnum.values()) {
            if (url.contains(jenkinsServerEnum.getUrl())) {
                userMap.put("userId", jenkinsServerEnum.getUser());
                userMap.put("userPassword", jenkinsServerEnum.getPassword());
            }
        }
        return userMap;
    }
}